
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sony_dvb_integration.h"
#include "sony_dvb_demod_monitor.h"
#include "sony_dvb_demod_monitorT.h"
#include "sony_dvb_demod_monitorT2.h"
#include "sony_dvb_demod_monitorC.h"
#include "Si2148_L3_API.h"
#include "mxl603.h"
#include "sony_i2c_user_define.h"
#include "i2c_gateway.h"


#define TUNER_RFLVLMON_DISABLE      1       /**< Define to disable RF level monitoring. */
#define SONY_MXL603_OFFSET_CUTOFF_HZ       50000
#define TUNER_IFAGCPOS  1
#define TUNER_MXL603_ID  2
#define TUNER_SI2148_ID  3

sony_i2c_t TunerI2C;
static sony_dvb_integration_t sony_demod_integration;
static sony_i2c_t demodI2C;
static sony_dvb_demod_t sony_demod;
static sony_dvb_tuner_t sony_tuner;
static user_i2c_t useri2c;
static const char *FormatResult (sony_result_t result)
{
    char *pErrorName = "UNKNOWN";
    switch (result) {
    case SONY_RESULT_OK:
        pErrorName = "OK";
        break;
    case SONY_RESULT_ERROR_TIMEOUT:
        pErrorName = "ERROR_TIMEOUT";
        break;
    case SONY_RESULT_ERROR_UNLOCK:
        pErrorName = "ERROR_UNLOCK";
        break;
    case SONY_RESULT_ERROR_CANCEL:
        pErrorName = "ERROR_CANCEL";
        break;
    case SONY_RESULT_ERROR_ARG:
        pErrorName = "ERROR_ARG";
        break;
    case SONY_RESULT_ERROR_I2C:
        pErrorName = "ERROR_I2C";
        break;
    case SONY_RESULT_ERROR_SW_STATE:
        pErrorName = "ERROR_SW_STATE";
        break;
    case SONY_RESULT_ERROR_HW_STATE:
        pErrorName = "ERROR_HW_STATE";
        break;
    case SONY_RESULT_ERROR_RANGE:
        pErrorName = "ERROR_RANGE";
        break;
    case SONY_RESULT_ERROR_NOSUPPORT:
        pErrorName = "ERROR_NOSUPPORT";
        break;
    case SONY_RESULT_ERROR_OTHER:
        pErrorName = "ERROR_OTHER";
        break;
    default:
        pErrorName = "ERROR_UNKNOWN";
        break;
    }
    return pErrorName;
}

static const char *FormatTsLock (sony_dvb_demod_lock_result_t tsLockResult)
{
    char *pName = "Unknown";
    switch (tsLockResult) {
    case DEMOD_LOCK_RESULT_NOTDETECT:
        pName = "Not detected";
        break;
    case DEMOD_LOCK_RESULT_LOCKED:
        pName = "Locked";
        break;
    case DEMOD_LOCK_RESULT_UNLOCKED:
        pName = "Unlocked";
        break;
    default:
        break;
    }
    return pName;
}

sony_result_t sony_dvb_init(int tunerID)
{
	sony_result_t result = SONY_RESULT_OK;

	/*------------------------------------------------------------------------------
	 Initialisation
	------------------------------------------------------------------------------*/

	memset(&useri2c,0,sizeof(user_i2c_t));
	memset(&sony_demod_integration,0,sizeof(sony_dvb_integration_t));
	memset(&demodI2C,0,sizeof(sony_i2c_t));
	memset(&sony_demod,0,sizeof(sony_dvb_demod_t));
	memset(&sony_tuner,0,sizeof(sony_dvb_tuner_t));
	memset(&TunerI2C,0,sizeof(sony_i2c_t));
	/* Setup tuner I2C interfaces. */
	i2c_gw_Create(&useri2c,SONY_DVB_DEMOD_ADDRESS,0x09,&TunerI2C);

	/* Setup demod I2C interfaces. */
	demodI2C.gwAddress = 0x00;
	demodI2C.gwSub = 0x00;      /* N/A */
	demodI2C.Read = sony_i2c_Read;
	demodI2C.Write = sony_i2c_Write;
	demodI2C.ReadRegister = sony_i2c_CommonReadRegister;
	demodI2C.WriteRegister = sony_i2c_CommonWriteRegister;
	demodI2C.WriteOneRegister = sony_i2c_CommonWriteOneRegister;
	demodI2C.user = (void *) &useri2c;

	Star_PL_Print("Driver Version %s, Built %s %s\n", sony_demod_driver_version, sony_demod_driver_build_date,
	    sony_demod_driver_build_time);

	/* Setup tuner */
	if(tunerID == TUNER_MXL603_ID)
	{
		result = Mxl603_Create(MXL603_I2C_ADDR, 16, &TunerI2C, 0,&sony_tuner);
		if(result != SONY_RESULT_OK)
		{
			Star_PL_Print ("Error: Unable to create Sony ASCOT2D tuner driver. (status=%d, %s)\r\n", result, FormatResult (result));
			return result;
		}
	}
	else if(tunerID == TUNER_SI2148_ID)
	{		
		result = Si2148_tuner_create(Si2148_BASE_ADDRESS,24, &TunerI2C, 0,&sony_tuner);
		if(result != SONY_RESULT_OK)
		{
			Star_PL_Print ("Error: Unable to create Sony ASCOT2D tuner driver. (status=%d, %s)\r\n", result, FormatResult (result));
			return result;
		}
	}
	else
	{
		return SONY_RESULT_ERROR_ARG;
	}

	/* Setup demodulator. */
	result = sony_dvb_integration_Create (SONY_DVB_20500kHz,SONY_DVB_DEMOD_ADDRESS, &demodI2C, &sony_demod, &sony_tuner, &sony_demod_integration);

	/* Configure demod driver for Sony ASCOT2D tuner IF. */
	sony_demod.iffreq_config.config_DVBT5 = DVB_DEMOD_MAKE_IFFREQ_CONFIG (3.60);
	sony_demod.iffreq_config.config_DVBT6 = DVB_DEMOD_MAKE_IFFREQ_CONFIG (3.60);
	sony_demod.iffreq_config.config_DVBT7 = DVB_DEMOD_MAKE_IFFREQ_CONFIG (4.20);
	sony_demod.iffreq_config.config_DVBT8 = DVB_DEMOD_MAKE_IFFREQ_CONFIG (4.57);//DVB_DEMOD_MAKE_IFFREQ_CONFIG (4.80);xuj
	sony_demod.iffreq_config.config_DVBC = DVB_DEMOD_MAKE_IFFREQ_CONFIG (4.90);

	/* T2 ITB setup. */
	sony_demod.iffreq_config.config_DVBT2_5 = DVB_DEMOD_MAKE_IFFREQ_CONFIG (3.60);
	sony_demod.iffreq_config.config_DVBT2_6 = DVB_DEMOD_MAKE_IFFREQ_CONFIG (3.60);
	sony_demod.iffreq_config.config_DVBT2_7 = DVB_DEMOD_MAKE_IFFREQ_CONFIG (4.20);
	sony_demod.iffreq_config.config_DVBT2_8 = DVB_DEMOD_MAKE_IFFREQ_CONFIG (4.57);//DVB_DEMOD_MAKE_IFFREQ_CONFIG (4.80);xuj

	/* Initialize the demod I2C */
	useri2c.handle = (uint32_t)&demodI2C;
	result = sony_i2c_initialize();
	if (result != SONY_RESULT_OK)
	{
		Star_PL_Print ("Error: Unable to initialise FEUSB I2C driver. (status=%d, %s)\r\n", result, FormatResult (result));
		return result;
	}

	/* Initialize the system. */
	result = sony_dvb_integration_Initialize (&sony_demod_integration);
	if (result != SONY_RESULT_OK)
	{
		Star_PL_Print ("Error: Unable to initialise the integration driver. (status=%d, %s)\r\n", result, FormatResult (result));
		return result;
	}

	/*demod config by xuj*/
	result = sony_dvb_demod_SetConfig (&sony_demod, DEMOD_CONFIG_TSERR_ENABLE, 1);
	if (result != SONY_RESULT_OK)
	{
		Star_PL_Print ("Error: Unable to configure DEMOD_CONFIG_TSERR_ENABLE. (status=%d, %s)\r\n", result, FormatResult (result));
		return result;
	}

	/* IFAGC setup. Modify to suit connected tuner. */
	/* IFAGC positive, value = 0. */
	
#ifdef TUNER_IFAGCPOS
	result = sony_dvb_demod_SetConfig (&sony_demod, DEMOD_CONFIG_IFAGCNEG, 0);
	if (result != SONY_RESULT_OK)
	{
		Star_PL_Print ("Error: Unable to configure IFAGCNEG. (status=%d, %s)\r\n", result, FormatResult (result));
		return result;
	}
#endif

	/* Spectrum Inversion setup. Modify to suit connected tuner. */
	/* Spectrum inverted, value = 1. */
#ifdef TUNER_SPECTRUM_INV
	result = sony_dvb_demod_SetConfig (&sony_demod, DEMOD_CONFIG_SPECTRUM_INV, 1);
	if (result != SONY_RESULT_OK)
	{
		Star_PL_Print ("Error: Unable to configure SPECTRUM_INV. (status=%d, %s)\r\n", result, FormatResult (result));
		return result;
	}
#endif

	/* RF level monitoring (RFAIN/RFAGC) enable/disable. */
	/* Default is enabled. 1: Enable, 0: Disable. */
#ifdef TUNER_RFLVLMON_DISABLE
	result = sony_dvb_demod_SetConfig (&sony_demod, DEMOD_CONFIG_RFLVMON_ENABLE, 0);
	if (result != SONY_RESULT_OK)
	{
		Star_PL_Print ("Error: Unable to configure RFLVMON_ENABLE. (status=%d, %s)\r\n", result, FormatResult (result));
		return result;
	}
#endif
	return result;
}

sony_result_t sony_dvb_term(void)
{
	sony_result_t result = SONY_RESULT_OK;
	/*------------------------------------------------------------------------------
	Closing / Shutdown
	------------------------------------------------------------------------------*/

	/* Finalize the device. */
	result = sony_dvb_integration_Finalize (&sony_demod_integration);
	if (result != SONY_RESULT_OK) {
		Star_PL_Print ("Error: Unable to finalise the integration driver. (status=%d, %s)\r\n", result, FormatResult (result));
		return SONY_RESULT_ERROR_SW_STATE;
	}

	/* Finalise the I2C */
	result = sony_i2c_finalize ();
	if (result != SONY_RESULT_OK) {
		Star_PL_Print ("Error: Unable to finalize FEUSB I2C driver. (status=%d, %s)\r\n", result, FormatResult (result));
		return SONY_RESULT_ERROR_I2C;
	}
	return SONY_RESULT_OK;
}

sony_result_t sony_dvb_tune(sony_dvb_tune_params_t * tuneParams)
{
	sony_result_t tuneResult = SONY_RESULT_OK;
	sony_result_t result = SONY_RESULT_OK;
	
	if(!tuneParams)
		return SONY_RESULT_ERROR_ARG;
	
	Star_PL_Print ("Tune to DVB-T/T2 signal at %lukHz.\r\n", tuneParams->centreFreqkHz);
	tuneResult = sony_dvb_integration_Tune(&sony_demod_integration,tuneParams);
#if 0
	/* Carrier offset compensation. */
	if ((tuneResult == SONY_RESULT_ERROR_TIMEOUT) || (tuneResult == SONY_RESULT_OK))
	{
		int32_t offsetkHz = 0;
		uint32_t stepkHz = (SONY_MXL603_OFFSET_CUTOFF_HZ + 500) / 1000;

		/* Monitor carrier offset. */
		result = sony_dvb_demod_monitor_CarrierOffset(sony_demod_integration.pDemod, &offsetkHz);
		if (result != SONY_RESULT_OK)
		{
			Star_PL_Print ("Error: Unable to tuner carrier offset. (status=%d, %s)\n", result, FormatResult (result));
			return SONY_RESULT_ERROR_SW_STATE;
		}
		Star_PL_Print ("tuner carrier offset detected. Centre=%lukHz, offset=%ldkHz, step=%lukHz.\n", tuneParams->centreFreqkHz,offsetkHz, stepkHz);

		/* Carrier recovery loop locked (demod locked), compensate for the offset and retry tuning. */
		stepkHz = (stepkHz + 1) / 2;
		if ((uint32_t) abs (offsetkHz) > stepkHz)
		{
			/* Tuners have only a fixed frequency step size (stepkHz), */
			/* therefore we must query the tuner driver to get the actual */
			/* centre frequency set by the tuner. */
			tuneParams->centreFreqkHz = (uint32_t) ((int32_t) sony_demod_integration.pTuner->frequency + offsetkHz);
			tuneParams->t2Params.tuneResult = 0; /* Clear result. */

			Star_PL_Print ("Re-tuning to compensate offset. New centre=%lukHz.\n", tuneParams->centreFreqkHz);
			tuneResult = sony_dvb_integration_Tune (&sony_demod_integration, tuneParams);
		}
	}
#endif
	if (tuneResult != SONY_RESULT_OK)
	{
		Star_PL_Print ("TS unlocked at %lukHz.\n", tuneParams->centreFreqkHz);
		return SONY_RESULT_ERROR_UNLOCK;
	}
	Star_PL_Print ("TS locked to DVB-T/T2 signal at %lukHz.\n", tuneParams->centreFreqkHz);

	return SONY_RESULT_OK;
	
}

sony_result_t sony_dvb_islocked()
{
	sony_result_t result;
	sony_dvb_demod_lock_result_t tsLock = DEMOD_LOCK_RESULT_NOTDETECT;
	if(sony_demod_integration.pDemod ==NULL)
		return SONY_RESULT_ERROR_ARG;
	result = sony_dvb_demod_monitor_TSLock (sony_demod_integration.pDemod, &tsLock);
	if (result != SONY_RESULT_OK)
	{
		Star_PL_Print ("TS staus=%s\r\n", FormatTsLock (tsLock));
		return  SONY_RESULT_ERROR_UNLOCK;
	}
	if(tsLock == DEMOD_LOCK_RESULT_LOCKED)
		return SONY_RESULT_OK;
	
	return SONY_RESULT_ERROR_UNLOCK;
}

sony_result_t sony_dvb_signalinfo(uint8_t *pQuality,uint32_t *pIFAGC,uint32_t *pBER)
{	
	sony_result_t result = SONY_RESULT_OK;
	
       if((sony_demod_integration.pDemod == NULL)||(pQuality == NULL)||(pIFAGC == NULL)||(pBER == NULL))
	   	return SONY_RESULT_ERROR_ARG;
	
	switch(sony_demod_integration.pDemod->system)
	{
		case SONY_DVB_SYSTEM_DVBT2:
		{
			result = sony_dvb_demod_monitorT2_Quality(sony_demod_integration.pDemod,pQuality);
			if(result != SONY_RESULT_OK)
			{
				Star_PL_Print("[sony_dvb_demod_monitorT2_Quality] -> failed!\n");
			}
			result = sony_dvb_demod_monitorT2_IFAGCOut(sony_demod_integration.pDemod,pIFAGC);
			if(result != SONY_RESULT_OK)
			{
				Star_PL_Print("[sony_dvb_demod_monitorT2_IFAGCOut] -> failed!\n");
			}
			result = sony_dvb_demod_monitorT2_PreBCHBER(sony_demod_integration.pDemod,pBER);
			if(result != SONY_RESULT_OK)
			{
				Star_PL_Print("[sony_dvb_demod_monitorT2_PreBCHBER] -> failed!\n");
			}
			
		}	
		break;
		case SONY_DVB_SYSTEM_DVBT:
		{
			result = sony_dvb_demod_monitorT_Quality(sony_demod_integration.pDemod,pQuality);
			if(result != SONY_RESULT_OK)
			{
				Star_PL_Print("[sony_dvb_demod_monitorT_Quality] -> failed!\n");
			}
			result = sony_dvb_demod_monitorT_IFAGCOut(sony_demod_integration.pDemod,pIFAGC);
			if(result != SONY_RESULT_OK)
			{
				Star_PL_Print("[sony_dvb_demod_monitorT_IFAGCOut] -> failed!\n");
			}
			result = sony_dvb_demod_monitorT_PreRSBER(sony_demod_integration.pDemod,pBER);
			if(result != SONY_RESULT_OK)
			{
				Star_PL_Print("[sony_dvb_demod_monitorT_PreRSBER] -> failed!\n");
			}
			*pBER = (*pBER)*100;
		}	
		break;
		case SONY_DVB_SYSTEM_DVBC:
		{
			int32_t pSNR = 0;
			result = sony_dvb_demod_monitorC_SNR(sony_demod_integration.pDemod,&pSNR);
			if(result != SONY_RESULT_OK)
			{
				Star_PL_Print("[sony_dvb_demod_monitorT_Quality] -> failed!\n");
			}
			if(pSNR<0)
				*pQuality = 0;
			else
				*pQuality = pSNR;
			result = sony_dvb_demod_monitorC_IFAGCOut(sony_demod_integration.pDemod,pIFAGC);
			if(result != SONY_RESULT_OK)
			{
				Star_PL_Print("[sony_dvb_demod_monitorT_IFAGCOut] -> failed!\n");
			}
			result = sony_dvb_demod_monitorC_PreRSBER(sony_demod_integration.pDemod,pBER);
			if(result != SONY_RESULT_OK)
			{
				Star_PL_Print("[sony_dvb_demod_monitorT_PreRSBER] -> failed!\n");
			}
			*pBER = (*pBER)*100;
		}	
		break;
		default:
			return SONY_RESULT_ERROR_ARG;
	}
	return  SONY_RESULT_OK;
}

